package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.service.OrdersService;
import com.sky.vo.*;
import com.sky.webSocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.weaver.ast.Or;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 夏帮连
 * @date: 2025/06/25
 * @description:
 * @version: 1.0
 */
@Service
@Slf4j
public class OrdersServiceImpl implements OrdersService {
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private WebSocketServer webSocketServer;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private DishMapper dishMapper;


    @Override
    public OrderSubmitVO submit(OrdersSubmitDTO ordersSubmitDTO) {
        /**
         * 1.处理异常情况：订单地址为空
         */
        Long addressBookId = ordersSubmitDTO.getAddressBookId();
        AddressBook addressBook = addressBookMapper.getById(addressBookId);
        if (addressBook == null) {
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
        /**
         * 2.购物车不能为空
         */
        Long userId = BaseContext.getCurrentId();
        ShoppingCart shoppingCart = ShoppingCart.builder().userId(userId).build();
        List<ShoppingCart> shoppingCartlist = shoppingCartMapper.list(shoppingCart);
        if (shoppingCartlist == null || shoppingCartlist.isEmpty()) {
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        //2.向订单表插入1条数据（用户不管买多少个商品，只要它提交就是一个订单，对应一条订单数据）
        //构造订单数据
        Orders order = new Orders();
        //OrdersSubmitDTO已经封装好了一些数据，所以进行一个对象的拷贝
        BeanUtils.copyProperties(ordersSubmitDTO,order);
        //设置剩余的参数：
        //用户的手机号，dto并没有给我们传递过来，通过地址簿id查询出地址数据，在地址数据中就包含用户的名字和手机号
        //    在前面异常判断中已经查过了，所以在这个地方直接取就可以。
        order.setPhone(addressBook.getPhone());
        order.setAddress(addressBook.getDetail());
        order.setConsignee(addressBook.getConsignee());//收货人
        //要求是字符串类型，这个地方返回的是Long类型，所以需要进行转化
        order.setNumber(String.valueOf(System.currentTimeMillis()));//订单号，使用当前系统时间的时间戳生成
        order.setUserId(userId);//当前订单是属于哪个用户的
        order.setStatus(Orders.PENDING_PAYMENT);//订单状态：此时是待付款
        order.setPayStatus(Orders.UN_PAID);//支付状态，用户刚完成下单所以是未支付状态
        order.setOrderTime(LocalDateTime.now());//下单时间
        //这个sql需要返回插入的主键值，在后面插入订单明细，在订单明细实体类中会使用当前这个订单的id
        orderMapper.insert(order);
        List<OrderDetail> orderDetailList=new ArrayList<>();
        for(ShoppingCart sc:shoppingCartlist){
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(sc,orderDetail);
            orderDetail.setOrderId(order.getId());
            orderDetailList.add(orderDetail);
        }
        orderDetailMapper.insertBatch(orderDetailList);
        shoppingCartMapper.delete(userId);
        //5.封装VO返回结果
        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                .id(order.getId())
                .orderNumber(order.getNumber())
                .orderAmount(order.getAmount())
                .orderTime(order.getOrderTime())
                .build();
        return orderSubmitVO;
    }

    @Override
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "ORDERPAID");
        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));
        String orderNumber = ordersPaymentDTO.getOrderNumber();
        LocalDateTime checkoutTime = LocalDateTime.now();
        Orders ordersDB=orderMapper.getByUserIdAndNumber(BaseContext.getCurrentId(),orderNumber);
        Orders orders = Orders.builder().payStatus(Orders.PAID).status(Orders.TO_BE_CONFIRMED).id(ordersDB.getId()).orderTime(checkoutTime).build();
        orderMapper.update(orders);
        Map map = new HashMap();
        map.put("type",1);
        map.put("orderId",ordersDB.getId());
        map.put("content","订单号："+orderNumber);
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
        return vo;
    }

    @Override
    public void reminder(Long id) {
        Orders orders=orderMapper.getById(id);
        Map map=new HashMap();
        map.put("type",2);
        map.put("orderId",id);
        map.put("content","订单号："+orders.getNumber());
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }

    @Override
    public void repetition(Long id) {
        Long userId = BaseContext.getCurrentId();
        List<ShoppingCart> shoppingCarts=new ArrayList<>();
        List<OrderDetail> orderDetails = orderDetailMapper.getByOrderId(id);
        for(OrderDetail orderDetail:orderDetails){
            ShoppingCart shoppingCart = new ShoppingCart();
            BeanUtils.copyProperties(orderDetail,shoppingCart,"id");
            shoppingCart.setCreateTime(LocalDateTime.now());
            shoppingCart.setUserId(userId);
            shoppingCarts.add(shoppingCart);
        }
        shoppingCartMapper.insertBatch(shoppingCarts);
    }

    @Override
    public PageResult pageQueryByUser(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        Page<Orders> page=orderMapper.page(ordersPageQueryDTO);
        List<OrderVO> orderVOS = new ArrayList();
        if (page!=null && page.getTotal()>0) {
            for (Orders orders : page) {
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders,orderVO);
                List<OrderDetail> orderDetails=orderDetailMapper.getByOrderId(orders.getId());
                orderVO.setOrderDetailList(orderDetails);
                orderVOS.add(orderVO);
            }
        }
        return new PageResult(page.getTotal(),orderVOS);
    }

    @Override
    public void cancel(Long id) {
        Orders ordersDB = orderMapper.getById(id);
        //判断是否存在订单
        if(ordersDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if(ordersDB.getStatus()>2){
            throw  new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        Orders orders = new Orders();
        //判断订单状态是不是待确认，如果是的话需要退款
        if(ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            orders.setPayStatus(Orders.REFUND);
        }
        orders.setId(ordersDB.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelTime(LocalDateTime.now());
        orders.setCancelReason("用户取消");
        orderMapper.update(orders);
    }

    @Override
    public void cancel(OrdersCancelDTO ordersCancelDTO) {
        Long id = ordersCancelDTO.getId();
        Orders ordersDB = orderMapper.getById(id);
        //判断是否存在订单
        if(ordersDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if(!ordersDB.getStatus().equals(Orders.CONFIRMED) && !ordersDB.getStatus().equals(Orders.DELIVERY_IN_PROGRESS)) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        Orders orders = new Orders();
        //判断订单状态是不是待确认，如果是的话需要退款
        if(ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            orders.setPayStatus(Orders.REFUND);
        }
        orders.setId(id);
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelTime(LocalDateTime.now());
        orders.setCancelReason(ordersCancelDTO.getCancelReason());
        orderMapper.update(orders);
    }

    @Override
    public OrderVO orderDetail(Long id) {
        OrderVO orderVO = new OrderVO();
        Orders orders = orderMapper.getById(id);
        BeanUtils.copyProperties(orders,orderVO);
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);
        orderVO.setOrderDetailList(orderDetailList);
        return orderVO;
    }

    @Override
    public OrderStatisticsVO statistics() {
        Integer deliveryInProcessCount=orderMapper.getByStatus(Orders.DELIVERY_IN_PROGRESS);
        Integer confirmedCount = orderMapper.getByStatus(Orders.CONFIRMED);
        Integer toBeConfirmedCount = orderMapper.getByStatus(Orders.TO_BE_CONFIRMED);
        return OrderStatisticsVO.builder().confirmed(confirmedCount).toBeConfirmed(toBeConfirmedCount).deliveryInProgress(deliveryInProcessCount).build();
    }

    @Override
    public void complete(Long id) {
        Orders orders = Orders.builder().id(id).status(Orders.COMPLETED).deliveryTime(LocalDateTime.now()).build();
        orderMapper.update(orders);
    }

    @Override
    public void reject(OrdersRejectionDTO ordersRejectionDTO) {
        Long id = ordersRejectionDTO.getId();
        Orders ordersDB = orderMapper.getById(id);
        //判断是否存在订单
        if(ordersDB==null || !ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        Orders orders = new Orders();
        orders.setPayStatus(Orders.REFUND);
        orders.setId(id);
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelTime(LocalDateTime.now());
        orders.setCancelReason(ordersRejectionDTO.getRejectionReason());
        orderMapper.update(orders);
    }

    @Override
    public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
        Orders orders = Orders.builder().id(ordersConfirmDTO.getId()).status(Orders.CONFIRMED).build();
        orderMapper.update(orders);
    }

    @Override
    public void delivery(Long id) {
        Orders ordersDB = orderMapper.getById(id);
        if(ordersDB==null || !ordersDB.getStatus().equals(Orders.CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        Orders order = Orders.builder().id(id).status(Orders.DELIVERY_IN_PROGRESS).build();
        orderMapper.update(order);
    }

    @Override
    public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        Page<Orders> page = orderMapper.page(ordersPageQueryDTO);
        // 部分订单状态，需要额外返回订单菜品信息，将Orders转化为OrderVO
        List<OrderVO> orderVOList = getOrderVOList(page);
        return new PageResult(page.getTotal(), orderVOList);
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        log.info("订单数据统计,begin:{},end:{}", begin, end);
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.equals(end)) {
            begin=begin.plusDays(1);
            dateList.add(begin);
        }
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        for (LocalDate date : dateList) {
            LocalDateTime beginDateTime=LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endDateTime=LocalDateTime.of(date, LocalTime.MAX);
            Integer orderCount=getOrderCount(beginDateTime,endDateTime,null);
            Integer validOrderCount=getOrderCount(beginDateTime,endDateTime, Orders.COMPLETED);
            orderCountList.add(orderCount);
            validOrderCountList.add(validOrderCount);
        }
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();
        Integer totalValidOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();
        Double orderCompleteRate=0.0;
        if (totalOrderCount!=0){
            orderCompleteRate=totalValidOrderCount.doubleValue()/totalOrderCount;
        }
        return OrderReportVO.builder()
                .dateList(StringUtils.join(dateList, ",")).orderCountList(StringUtils.join(orderCountList, ","))
                .validOrderCountList(StringUtils.join(validOrderCountList, ",")).totalOrderCount(totalOrderCount).validOrderCount(totalValidOrderCount)
                .orderCompletionRate(orderCompleteRate).build();
    }

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        // 当前集合用于存放从begin到end范围内的每天的日期
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while(!begin.equals(end)){
            // 日期计算，计算指定日期的后一天对应的日期
            begin = begin.plusDays(1);
            dateList.add(begin);
        }

        // 存放每天的营业额
        List<Double> turnoverList = new ArrayList<>();
        for (LocalDate date : dateList) {
            // 查询date日期对应的营业额，营业额是指：状态为“已完成”的订单金额合计
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
            // select sum(amount) from orders where order_time > beginTime and order_time < endTime and status = 5

            Map map = new HashMap<>();
            map.put("begin", beginTime);
            map.put("end", endTime);
            map.put("status", Orders.COMPLETED);
            Double turnover = orderMapper.countByTurnOverMap(map);
            turnoverList.add(turnover);
        }
        log.info("营业额数据为:{}",turnoverList);
        // 封装返回结果
        return TurnoverReportVO
                .builder()
                .dateList(StringUtils.join(dateList, ","))
                .turnoverList(StringUtils.join(turnoverList, ","))
                .build();
    }

    @Override
    public SalesTop10ReportVO salesTop10(LocalDate begin, LocalDate end) {
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        List<GoodsSalesDTO> salesTop10 = orderMapper.getSalesTop10(beginTime, endTime);
        List<String> names = salesTop10.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
        String nameList = StringUtils.join(names, ",");
        log.info("销量前10为：{}",salesTop10);
        List<Integer> numbers = salesTop10.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());
        String numberList = StringUtils.join(numbers, ",");

        return SalesTop10ReportVO
                .builder()
                .nameList(nameList)
                .numberList(numberList)
                .build();
    }

    @Override
    public BusinessDataVO getBusinessData() {
        LocalDate localDate = LocalDate.now();
        LocalDateTime begin = LocalDateTime.of(localDate, LocalTime.MIN);
        LocalDateTime end = LocalDateTime.of(localDate, LocalTime.MAX);
        // 新增用户数
        Integer newUsers = userMapper.userCount(begin, end);
        //有效订单数
        Map map=new HashMap();
        map.put("begin", begin);
        map.put("end", end);
        map.put("status", Orders.COMPLETED);
        Integer validOrderCount = orderMapper.countByOrderMap(map);
        //营业额
        Double turnover = orderMapper.countByTurnOverMap(map);
        //订单完成率
        map.put("status",null);
        Integer orderCount = orderMapper.countByOrderMap(map);
        Double orderCompleteRate=validOrderCount.doubleValue()/orderCount;
        //平均客单价
        Double unitPrice=turnover/validOrderCount;
        return BusinessDataVO.builder().newUsers(newUsers).validOrderCount(validOrderCount)
                .orderCompletionRate(orderCompleteRate).unitPrice(unitPrice).turnover(turnover).build();
    }

    @Override
    public SetmealOverViewVO getOverviewSetmeals() {
        Integer discontinued=setmealMapper.countByStatus(StatusConstant.DISABLE);
        Integer sold=setmealMapper.countByStatus(StatusConstant.ENABLE);
        return SetmealOverViewVO.builder().discontinued(discontinued).sold(sold).build();
    }

    @Override
    public DishOverViewVO getOverviewDishes() {
        Integer discontinued=dishMapper.countByStatus(StatusConstant.DISABLE);
        Integer sold=dishMapper.countByStatus(StatusConstant.ENABLE);
        return DishOverViewVO.builder().discontinued(discontinued).sold(sold).build();
    }

    @Override
    public OrderOverViewVO getOverviewOrders() {
        //全部订单数量
        Integer allOrders=orderMapper.getOrdersCount(null);
        //已取消数量
        Integer cancelledOrders=orderMapper.getOrdersCount(Orders.CANCELLED);
        //已完成数量
        Integer completedOrders=orderMapper.getOrdersCount(Orders.COMPLETED);
        //待派送数量
        Integer deliveredOrders=orderMapper.getOrdersCount(Orders.CONFIRMED);
        //待接单数量
        Integer waitingOrders=orderMapper.getOrdersCount(Orders.TO_BE_CONFIRMED);
        return OrderOverViewVO.builder()
                .waitingOrders(waitingOrders)
                .allOrders(allOrders)
                .cancelledOrders(cancelledOrders)
                .deliveredOrders(deliveredOrders)
                .completedOrders(completedOrders)
                .build();
    }

    private Integer getOrderCount(LocalDateTime beginDateTime, LocalDateTime endDateTime,Integer status) {
        Map map = new HashMap();
        map.put("begin", beginDateTime);
        map.put("end", endDateTime);
        map.put("status", status);
        return orderMapper.countByOrderMap(map);
    }

    private List<OrderVO> getOrderVOList(Page<Orders> page) {
        List<OrderVO> orderVOList = new ArrayList<>();

        List<Orders> ordersList = page.getResult();
        if (!CollectionUtils.isEmpty(ordersList)) {
            for (Orders orders : ordersList) {
                // 将共同字段复制到OrderVO
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders, orderVO);
                String orderDishes = getOrderDishesStr(orders);

                // 将订单菜品信息封装到orderVO中，并添加到orderVOList
                orderVO.setOrderDishes(orderDishes);
                orderVOList.add(orderVO);
            }
        }
        return orderVOList;
    }

    private String getOrderDishesStr(Orders orders) {
        // 查询订单菜品详情信息（订单中的菜品和数量）
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(orders.getId());
        // 将每一条订单菜品信息拼接为字符串（格式：宫保鸡丁*3；）
        List<String> orderDishList = orderDetailList.stream().map(x -> {
            String orderDish = x.getName() + "*" + x.getNumber() + ";";
            return orderDish;
        }).collect(Collectors.toList());

        // 将该订单对应的所有菜品信息拼接在一起
        return String.join("", orderDishList);
    }
}

